#ifndef __ENGINE_TIMEDMAP_included
#define __ENGINE_TIMEDMAP_included

#include <map>
#include <list>
#include <boost/thread/mutex.hpp>
#include "../port/System.h"

using namespace std;

namespace Engine {

template <class KeyT, class ValueT>
struct _TimedObjectContainer {
	KeyT mKey;
	Util::CSystem::TimeType mValidTime;
	ValueT mValue;
};

template <class KeyT, class ValueT>
class CTimedMap {

public :

	typedef _TimedObjectContainer<KeyT, ValueT> TimedObjectContainer;
	typedef typename list<TimedObjectContainer>::iterator ValueIter;

private :

	list<TimedObjectContainer> mList;
	map<KeyT, ValueIter> mMap;
	boost::mutex mMutex;

	int mValidSeconds;

	void refresh() {

		Util::CSystem::TimeType now = Util::CSystem::GetCurrentSeconds();
		// try to clean time-out session
		ValueIter ii;
		while((ii = mList.begin()) != mList.end()) {
			if((*ii).mValidTime < now) {
				std::map<KeyT, ValueIter>::iterator i = mMap.find((*ii).mKey);
				if(i != mMap.end()) mMap.erase(i);
				mList.erase(ii);
			}
			else {
				break;
			}
		}
	}

public :

	CTimedMap(int valid_secs) : mValidSeconds(valid_secs) { }

	int Size() { return mList.size(); }

	void Add(KeyT& k, ValueT v) {
		boost::mutex::scoped_lock lock(mMutex);

		TimedObjectContainer container;
		container.mKey = k;
		container.mValidTime = Util::CSystem::GetCurrentSeconds() + mValidSeconds;
		container.mValue = v;

		mList.push_back(container);
		ValueIter ii = mList.end();
		ii == --ii;
		mMap[k] = ii;
	}

	ValueT Get(KeyT& k) {

		boost::mutex::scoped_lock lock(mMutex);

		refresh();

		std::map<KeyT, ValueIter>::iterator i = mMap.find(k);
		if(i != mMap.end()) {
			ValueIter ii = i->second;
			TimedObjectContainer container = *ii;
			container.mValidTime = Util::CSystem::GetCurrentSeconds() + mValidSeconds;
			mList.erase(ii);
			mList.push_back(container);
			ii = mList.end();
			ii == --ii;
			mMap[k] = ii;
			return container.mValue;
		}
		else return ValueT();
	}

	ValueT Pop(KeyT& k) {

		boost::mutex::scoped_lock lock(mMutex);

		refresh();

		std::map<KeyT, ValueIter>::iterator i = mMap.find(k);
		if(i != mMap.end()) {
			ValueIter ii = i->second;
			ValueT v = (*ii).mValue;
			mMap.erase(i);
			mList.erase(ii);
			return v;
		}
		else return ValueT();
	}

	ValueIter Begin() { return mList.begin(); }
	ValueIter End() { return mList.end(); }

	void Lock() { mMutex.lock(); }
	void Unlock() { mMutex.unlock(); }
};

}

#endif // __ENGINE_TIMEDMAP_included